import {
    WebGLRenderer, Scene, PerspectiveCamera, Texture, Mesh, MeshStandardMaterial, Color, MeshBasicMaterial, TextureLoader, Raycaster, Vector2,
} from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

//GLTF模型加载器
const gltfLoader = new GLTFLoader();
//射线,基于鼠标与相机建立射线,用于选择对象
const raycaster = new Raycaster();
//鼠标在裁剪空间中的点位
const pointer = new Vector2();

export default class MachineRoom {
    //渲染器
    renderer: WebGLRenderer;
    //场景
    scene: Scene;
    //相机
    camera: PerspectiveCamera;
    //相机轨道控制器
    controls: OrbitControls;
    //模型目录
    modelPath: string;
    //模型纹理集合
    maps: Map<string, Texture> = new Map();

    //机柜对象集合
    cabinets: Mesh[] = [];
    curCabinets: Mesh = null;
    onMouseEnterEvent = (obj: Mesh, e: {}) => { };
    onMouseLeaveEvent = (obj: Mesh, e: {}) => { };
    onMouseMoveEvent = (obj: Mesh, e: {}) => { };


    constructor(canvas: HTMLCanvasElement, modelPath: string) {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        this.renderer = new WebGLRenderer({ canvas: canvas });
        this.scene = new Scene();
        this.camera = new PerspectiveCamera(70, canvas.width / canvas.height, 0.1, 1000);
        this.camera.position.set(0, 10, 15);
        this.camera.lookAt(0, 0, 0);
        this.controls = new OrbitControls(
            this.camera,
            this.renderer.domElement//?这个是canvas吧
        );
        this.modelPath = modelPath;

        //添加高亮贴图
        this._crtTexture('cabinet-hover.jpg');
    }

    //加载GLTF模型
    loadGLTF(modelName: string) {
        gltfLoader.load(this.modelPath + modelName, (data) => {
            data.scene.children.forEach((obj: Mesh) => {
                const { map, color } = obj.material as MeshStandardMaterial;
                this._changeMat(obj, map, color);

                if (obj.name.includes('cabinet')) {
                    this.cabinets.push(obj);
                }
            });
            this.scene.add(...data.scene.children);
        });
    }

    //修改材质
    _changeMat(obj: Mesh, map: Texture, color: Color) {
        if (map == null) {
            //创建一个纯色
            obj.material = new MeshBasicMaterial({ color: color });
        } else {
            //MeshBasicMaterial:无光照贴图
            if (map.name == 'floor01.jpg' || map.name == 'floor02.jpg') {
                obj.material = new MeshBasicMaterial({
                    map: this._crtTexture(map.name),
                });
            } else {
                //不知道为什么这个贴图没法进行更换, 只能用原本固定的
                // (obj.material as MeshStandardMaterial).setValues({
                //     map: this._crtTexture('cabinet-hover.jpg')
                // });

                obj.material = new MeshBasicMaterial({
                    map: this._crtTexture(map.name),
                });
            }
        }
    }

    //建立纹理
    _crtTexture(imageName: string) {
        let curTexture = this.maps.get(imageName);
        if (curTexture == null) {
            curTexture = new TextureLoader().load(this.modelPath + imageName);
            curTexture.flipY = false;
            curTexture.wrapS = 1000;
            curTexture.wrapT = 1000;
            this.maps.set(imageName, curTexture);
        }
        return curTexture;
    }

    //获取裁剪坐标
    _getViewToWorld(x: number, y: number) {
        const { width, height } = this.renderer.domElement;
        pointer.set(
            (x / width) * 2 - 1,
            -(y / height) * 2 + 1,
        );
        return pointer;
    }

    //选择机箱
    selectCabinet(x: number, y: number) {
        const { cabinets, curCabinets, maps } = this;

        raycaster.setFromCamera(this._getViewToWorld(x, y), this.camera);

        const intersect = raycaster.intersectObjects(cabinets)[0];

        if (intersect != null) {
            const intersectObj = intersect.object as Mesh;
            //之前没有
            if (curCabinets == null) {
                //添加新的
                this.onMouseEnterEvent(intersectObj, { x: x, y: y });
                (intersectObj.material as MeshStandardMaterial).setValues({
                    map: maps.get('cabinet-hover.jpg'),
                });
                this.curCabinets = intersectObj;
            } else {
                //之前有且不相同
                if (intersect.object !== curCabinets) {
                    //去除旧的
                    this.onMouseLeaveEvent(curCabinets, { x: x, y: y });
                    (curCabinets.material as MeshStandardMaterial).setValues({
                        map: maps.get('cabinet.jpg'),
                    });
                    //添加新的
                    this.onMouseEnterEvent(intersectObj, { x: x, y: y });
                    (intersectObj.material as MeshStandardMaterial).setValues({
                        map: maps.get('cabinet-hover.jpg'),
                    });
                    this.curCabinets = intersectObj;
                } else {
                    this.onMouseMoveEvent(curCabinets, { x: x, y: y });
                }
            }

        } else {
            if (curCabinets != null) {
                //去除旧的
                this.onMouseLeaveEvent(curCabinets, { x: x, y: y });
                (curCabinets.material as MeshStandardMaterial).setValues({
                    map: maps.get('cabinet.jpg'),
                });
                this.curCabinets = null;
            }
        }
    }

    animate() {
        this.renderer.render(this.scene, this.camera);
        requestAnimationFrame(() => { this.animate(); });
    }
}